using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Collections.Specialized;

[Themeable(true)]
public partial class LookupControl : System.Web.UI.UserControl, IPostBackEventHandler
{
	private LookupClass _lkClass;
	private bool _enabled = true;
	private bool _hidden = false;
    private string _lookupClass = string.Empty;
	private string _cssClass = string.Empty;
	private string _disabledCssClass = string.Empty;
	private string _itemCssClass = string.Empty;
	private LookupControlItem[] _items = null;
	private string _lookupDialogUrl = string.Empty;
	private string _orgName = string.Empty;
	private Unit _width = new Unit(100, UnitType.Percentage);
	private Unit _height = new Unit(22, UnitType.Pixel);
	private bool _allowMultiSelect = false;
    private bool _autoPostBack = false;
    private string _onClientChange = string.Empty;

    public event LookupItemChanged LookupItemChanged;
    public NameValueCollection _queryString = new NameValueCollection();

    protected void Page_Load(object sender, EventArgs e)
    {
		if(string.IsNullOrEmpty(this.LookupClassName))
		{
			string message = (string)GetLocalResourceObject("lookupClassNameMissing");
			throw new ArgumentException(message);
		}
        
        this.plhItems.SetRenderMethodDelegate(new RenderMethod(this.RenderItems));
		
		if(IsPostBack)
		{
			LoadState();
		}
    }

	private void LoadState()
	{	
		if (this.ViewState["Enabled"] != null)
		{
			this._enabled = (bool)this.ViewState["Enabled"];
		}

		if (this.ViewState["LookupClass"] != null)
		{
			this._lookupClass = (string)this.ViewState["LookupClass"];
		}
		
		if(this.ViewState["LkClass"] != null)
		{
			this._lkClass = (LookupClass)this.ViewState["LkClass"];
		}

		if (this.ViewState["Width"] != null)
		{
			this._width = (Unit)this.ViewState["Width"];
		}

		if (this.ViewState["Height"] != null)
		{
			this._height = (Unit)this.ViewState["Height"];
		}
		
		if(this.ViewState["AllowMultiSelect"] != null)
		{
			this._allowMultiSelect = (bool)this.ViewState["AllowMultiSelect"];
		}

        if (this.ViewState["AutoPostBack"] != null)
        {
            this._autoPostBack = (bool)this.ViewState["AutoPostBack"];
        }

        if (this.ViewState["QueryString"] != null)
        {
            this._queryString = (NameValueCollection)this.ViewState["QueryString"];
        }
	}

	private void SaveState()
	{
		this.ViewState["Enabled"] = this._enabled;
		this.ViewState["LookupClass"] = this._lookupClass;
		this.ViewState["LkClass"] = this._lkClass;
		this.ViewState["Width"] = this._width;
		this.ViewState["Height"] = this._height;
		this.ViewState["AllowMultiSelect"] = this._allowMultiSelect;
        this.ViewState["AutoPostBack"] = this._autoPostBack;
        this.ViewState["QueryString"] = this._queryString;
	}
	
	private void RegisterScripts()
    {
        Type thisType = this.GetType();
		
		String scriptName = "common.js";
		String scriptUrl = ResolveUrl("ControlScripts/common.js");

		if (!Page.ClientScript.IsClientScriptIncludeRegistered(typeof(Page), scriptName))
        {
            Page.ClientScript.RegisterClientScriptInclude(typeof(Page), scriptName, ResolveClientUrl(scriptUrl));
        }

		scriptName = "xmlutil.js";
		scriptUrl = ResolveUrl("ControlScripts/xmlutil.js");

		if (!Page.ClientScript.IsClientScriptIncludeRegistered(typeof(Page), scriptName))
		{
			Page.ClientScript.RegisterClientScriptInclude(typeof(Page), scriptName, ResolveClientUrl(scriptUrl));
		}		

		scriptName = "LookupControl.js";
		scriptUrl = ResolveUrl("ControlScripts/LookupControl.js");

		if (!Page.ClientScript.IsClientScriptIncludeRegistered(thisType, scriptName))
		{
			Page.ClientScript.RegisterClientScriptInclude(thisType, scriptName, ResolveClientUrl(scriptUrl));
		}

        string changePostBack = string.Empty;
        if (this.AutoPostBack)
        {
            changePostBack = Page.ClientScript.GetPostBackEventReference(this, "LookupControl_LookupItemChanged");
        }
		
		string initFunction = this.ClientID + "_Init";
        string attachBlockStart = "function " + initFunction + "(){var lookup = document.getElementById('" + this.ClientID + "');";
		string attachLookupControl_GetValues = "lookup.getValues = LookupControl_GetValues;";
		string attachLookupControl_SetValues = "lookup.setValues = LookupControl_SetValues;";
		string attachLookupControl_RemoveValues = "lookup.removeValues = LookupControl_RemoveValues;";
		string attachLookupControl_GetIconUrl = "lookup.getIconUrl = LookupControl_GetIconUrl;";
		string attachLookupControl_GetOpenUrl = "lookup.getOpenUrl = LookupControl_GetOpenUrl;";
        string attachLookupControl_BrowseForLookup = "lookup.browseForLookup = function(){ var ret = LookupControl_BrowseForLookup(this); if(ret != 1)" + changePostBack + "; return ret;};";
		string attachLookupControl_GetItemXml = "lookup.getItemXml = function(){var text = document.getElementById('" + this.hdnItems.ClientID + "').value; if(!IsNull(text) && text!=\"\"){ text = HtmlDecode(text) } return text;};";
		string attachLookupControl_SetItemXml = "lookup.setItemXml = function(xml){ if(!IsNull(xml) && xml!=\"\"){ xml = HtmlEncode(xml) } document.getElementById('" + this.hdnItems.ClientID + "').value = xml;};";
		string attachLookupControl_LookupClass = "lookup.lookupClass = '" + this.LookupClassName + "';";
		string attachLookupControl_LookupDialogUrl = "lookup.lookupDialogUrl = '" + this.LookupDialogUrl + "';";
		string attachLookupControl_CssClass = "lookup.cssClass = '" + this.CssClass + "';";
		string attachLookupControl_DisabledCssClass = "lookup.disabledCssClass = '" + this.DisabledCssClass + "';";
		string attachLookupControl_ItemCssClass = "lookup.itemCssClass = '" + this.ItemCssClass + "';";
		string attachLookupControl_DivLookup = "lookup.divLookup = document.getElementById('" + this.pnlLookup.ClientID + "');";
		string attachLookupControl_OrgName = "lookup.orgName = '" + this.OrgName + "';";
		string attachLookupControl_AllowMultiSelect = "lookup.allowMultiSelect = '" + this.AllowMultiSelect.ToString().ToLower() + "';";
        string attachLookupControl_OnClientChange = string.IsNullOrEmpty(this.OnClientChange) ? string.Empty : "lookup.onClientChange = " + this.OnClientChange + ";";
        string attachLookupControl_QueryStrings = "lookup.queryStrings = new Array();";
        for (int I = 0; I < this.QueryString.Count; I++)
        {
            attachLookupControl_QueryStrings += "lookup.queryStrings[" + I + "] = new Object();";
            attachLookupControl_QueryStrings += "lookup.queryStrings[" + I + "].Name = '" + this.QueryString.GetKey(I) + "';";
            attachLookupControl_QueryStrings += "lookup.queryStrings[" + I + "].Value = '" + this.QueryString[I] + "';";
        }
        string attachObjectAttrs = string.Empty;
		foreach(LookupObject lkObject in this.LookupClass.Objects)
		{
			string attachOpenUrl = "lookup.openUrlFormatFor" + lkObject.TypeCode + " = '" + lkObject.OpenUrl + "';";
			string attachIcon = "lookup.iconUrlFor" + lkObject.TypeCode + " = '" + this.ResolveClientUrl(lkObject.Icon) + "';";

            attachObjectAttrs += attachOpenUrl + attachIcon;
		}
        string attachBlockEnd = "}";
		string initHandler = attachBlockStart + attachLookupControl_GetValues + attachLookupControl_SetValues + attachLookupControl_GetIconUrl + attachLookupControl_GetOpenUrl
		 + attachLookupControl_RemoveValues + attachLookupControl_BrowseForLookup + attachLookupControl_GetItemXml + attachLookupControl_SetItemXml + attachLookupControl_DivLookup
		 + attachLookupControl_LookupClass + attachLookupControl_LookupDialogUrl + attachLookupControl_CssClass + attachLookupControl_AllowMultiSelect
         + attachLookupControl_DisabledCssClass + attachLookupControl_ItemCssClass + attachLookupControl_OrgName + attachLookupControl_QueryStrings + attachLookupControl_OnClientChange
         + attachObjectAttrs + attachBlockEnd;
		string initCall = initFunction + "();";
		string attachInitHandler = "attachEndRequestHandler( " + initFunction + ");";
		string script = initHandler + attachInitHandler + initCall;
		
		Page.ClientScript.RegisterStartupScript(this.GetType(), Guid.NewGuid().ToString(), script, true);
	}

    public NameValueCollection QueryString
    {
        get
        {
            return _queryString;
        }
    }

	public LookupControlItem[] Items
	{
		get
		{
			if(_items == null)
			{
				_items = DeserializeItems();
			}
			return _items;
		}
		set
		{
			//if(value.Length > 1)
			//{
			//    throw new System.NotImplementedException();
			//}
			_items = value;
			foreach (LookupControlItem item in _items)
			{
				LookupObject lkObject = GetObjectByType(item.TypeName, item.TypeCode);
				if (lkObject == null)
				{
					string message = (string)GetLocalResourceObject("lookupTypeMissing");
					throw new ArgumentException(message);
				}
				item.TypeCode = lkObject.TypeCode;
				item.TypeName = lkObject.Name;
			}
			SerializeItems(_items);
		}
	}

	private LookupObject GetObjectByType(string typeName, int typeCode)
	{
		LookupObject lkObject = null;
		foreach (LookupObject lkObj in this.LookupClass.Objects)
		{
			if (lkObj.Name == typeName || lkObj.TypeCode == typeCode)
			{
				lkObject = lkObj;
				break;
			}
		}
		return lkObject;
	}

	public override string ClientID
	{
		get
		{
			return tblLookup.ClientID;
		}
	}

	public bool AllowMultiSelect
	{
		get { return _allowMultiSelect; }
		set { _allowMultiSelect = value; }
	}

    public bool AutoPostBack
    {
        get { return _autoPostBack; }
        set { _autoPostBack = value; }
    }

	private void SerializeItems(LookupControlItem[] oItems)
	{
		XmlDocument xDoc = new XmlDocument();
		XmlElement docElement = xDoc.CreateElement("Items");
		xDoc.AppendChild(docElement);
		foreach (LookupControlItem oItem in oItems)
		{
			XmlElement itemElement = xDoc.CreateElement("LookupItem");
			xDoc.DocumentElement.AppendChild(itemElement);
			XmlElement nameElement = xDoc.CreateElement("Name");
			nameElement.InnerText = oItem.Name;
			itemElement.AppendChild(nameElement);
			XmlElement guidElement = xDoc.CreateElement("Guid");
			//guidElement.InnerText = oItem.Guid.ToString();
            guidElement.InnerText = "{" + oItem.Guid.ToString().ToUpper() + "}";
			itemElement.AppendChild(guidElement);
			XmlElement typeCodeElement = xDoc.CreateElement("TypeCode");
			typeCodeElement.InnerText = oItem.TypeCode.ToString();
			itemElement.AppendChild(typeCodeElement);
			XmlElement typeNameElement = xDoc.CreateElement("TypeName");
			typeNameElement.InnerText = oItem.TypeName.ToString();
			itemElement.AppendChild(typeNameElement);
		}
        string s = HttpUtility.HtmlEncode(xDoc.OuterXml);
        s = s.Replace("&#160;", "&nbsp;");
        s = s.Replace("&#60;", "&lt;");
        s = s.Replace("&#62;", "&gt;");
        s = s.Replace("&#38;", "&amp;");
        s = s.Replace("&#34;", "&quot;");
        hdnItems.Value = s;
	}
	
	private LookupControlItem[] DeserializeItems()
	{
		List<LookupControlItem> listItems = new List<LookupControlItem>();
		if(!string.IsNullOrEmpty(hdnItems.Value))
		{
			string xmlValue = HttpUtility.HtmlDecode(hdnItems.Value);
			XmlDocument xDoc = new XmlDocument();
			xDoc.LoadXml(xmlValue);
			foreach(XmlElement itemElement in xDoc.DocumentElement.ChildNodes)
			{
				LookupControlItem oItem = new LookupControlItem();
				foreach(XmlElement propertyNode in itemElement.ChildNodes)
				{
					if(propertyNode.Name == "Name")
					{
						oItem.Name = HttpUtility.HtmlDecode(propertyNode.InnerText);
					}
					else if(propertyNode.Name == "Guid")
					{
						oItem.Guid = new Guid(propertyNode.InnerText);
					}
					else if(propertyNode.Name == "TypeCode")
					{
						oItem.TypeCode = Convert.ToInt32(propertyNode.InnerText);
					}
					else if (propertyNode.Name == "TypeName")
					{
						oItem.TypeName = propertyNode.InnerText;
					}
				}
				listItems.Add(oItem);
			}
		}
		return listItems.ToArray();
	}
	
	protected override void OnPreRender(EventArgs e)
	{
		base.OnPreRender(e);
		
		string cssClass = string.Empty;
		
		if(this.Enabled)
		{
			this.btnLookup.ImageUrl = ResolveUrl("ControlImages/lc_lookupbtn.gif");
			this.btnLookup.Attributes.Add("onmouseover", "this.src='" + ResolveUrl("ControlImages/lc_lookupbtnh.gif") + "'");
			this.btnLookup.Attributes.Add("onmouseout", "this.src='" + ResolveUrl("ControlImages/lc_lookupbtn.gif") + "'");
			this.btnLookup.Attributes.Add("onclick", "document.getElementById('" + this.ClientID + "').browseForLookup()");
			cssClass = this.CssClass;
		}
		else
		{
			this.btnLookup.ImageUrl = ResolveUrl("ControlImages/lc_lookupbtnd.gif");			
			this.btnLookup.Attributes.Remove("onmouseover");
			this.btnLookup.Attributes.Remove("onmouseout");
			this.btnLookup.Attributes.Remove("onclick");
			cssClass = this.DisabledCssClass;
		}
		
		if (!string.IsNullOrEmpty(cssClass))
		{
			this.tblLookup.Attributes.Add("class", cssClass);
			this.pnlLookup.Attributes.Add("class", cssClass);
			this.btnLookup.Attributes.Add("class", cssClass);
		}
		else
		{
			this.tblLookup.Attributes.Remove("class");
			this.pnlLookup.Attributes.Remove("class");
			this.btnLookup.Attributes.Remove("class");
		}

		this.SaveState();

		this.RegisterScripts();

        this.tblLookup.Attributes.Add("onkeydown", "LookupControl_KeyDown(this)");

		if(this.Hidden)
		{
			this.tblLookup.Style.Add(HtmlTextWriterStyle.Display, "none");
		}
		else
		{
			this.tblLookup.Style.Remove(HtmlTextWriterStyle.Display);
		}
		
		if(this.Width != null && !this.Width.IsEmpty)
		{
			this.tblLookup.Style.Add(HtmlTextWriterStyle.Width, this.Width.ToString());
		}
		
		if(this.Height != null && !this.Height.IsEmpty)
		{
			this.tblLookup.Style.Add(HtmlTextWriterStyle.Height, this.Height.ToString());
		}
	}
	
	protected void RenderItems(HtmlTextWriter writer, Control container)
	{
		LookupClass lkClass = LookupClass;
		LookupObject lkObject = null;		
		
		bool first = true;
		
		foreach(LookupControlItem item in this.Items)
		{
			if (!first)
			{
				writer.Write(" ");
			}
			else
			{
				first = false;
			}
			writer.Write("<span");
			writer.WriteAttribute("class", this.ItemCssClass);
			writer.WriteAttribute("oid", item.Guid.ToString());
			writer.WriteAttribute("otype", item.TypeCode.ToString());
			
			if(lkObject == null || lkObject.TypeCode != item.TypeCode)
			{
				foreach (LookupObject _lkObject in lkClass.Objects)
				{
					if(_lkObject.TypeCode == item.TypeCode)
					{
						lkObject = _lkObject;
						break;
					}
					else if(_lkObject.Name == item.TypeName)
					{
						lkObject = _lkObject;
						break;
					}
				}
			}
			
			string url = string.Format(lkObject.OpenUrl, "{" + item.Guid.ToString() + "}");
			writer.WriteAttribute("onclick", "OpenWindow('" + url + "')");
			
			writer.Write(">");
			
			string innerHtml = string.Empty;
			if(!string.IsNullOrEmpty(lkObject.Icon))
			{
				innerHtml += "<img class='" + this.ItemCssClass + "' src='" + this.ResolveClientUrl(lkObject.Icon) + "'/>";
			}
			innerHtml += HttpUtility.HtmlEncode(item.Name);
			
			writer.Write(innerHtml);
			
			writer.Write("</span>");
		}
	}
	
	public string CssClass
	{
		get { return _cssClass; }
		set { _cssClass = value; }
	}

	public string DisabledCssClass
	{
		get { return _disabledCssClass; }
		set { _disabledCssClass = value; }
	}

	public string ItemCssClass
	{
		get { return _itemCssClass; }
		set { _itemCssClass = value; }
	}
	
	[MergableProperty(false)]
	[ParenthesizePropertyName(true)]
	[Filterable(false)]
	public string LookupClassName
	{
		get
		{
			return _lookupClass;
		}
		set
		{
			_lookupClass = value;
		}
	}

	private LookupClass LookupClass
	{
		get
		{
			if (_lkClass == null || _lkClass.Name != _lookupClass)
			{
				LookupClassLoader lkLoader = new LookupClassLoader(this.OrgName);
				_lkClass = lkLoader.GetByName(_lookupClass);
			}
			return _lkClass;
		}
	}
	
	public string LookupDialogUrl
	{
		get
		{
			if(string.IsNullOrEmpty(this._lookupDialogUrl))
			{
				this._lookupDialogUrl = "Pages/LookupDialog.aspx";
			}
			return _lookupDialogUrl;
		}
		set { _lookupDialogUrl = value; }
	}

	public string OrgName
	{
		get { return _orgName; }
		set { _orgName = value; }
	}
	
	public bool Enabled
	{
		get
		{
			return _enabled;
		}
		set
		{
			_enabled = value;
		}
	}
	
	public bool Hidden
	{
		get
		{
			return _hidden;
		}
		set
		{
			_hidden = value;
		}
	}

	public Unit Width
	{
		get { return _width; }
		set { _width = value; }
	}

	public Unit Height
	{
		get { return _height; }
		set { _height = value; }
	}
    
    public string OnClientChange
    {
        get { return _onClientChange; }
        set { _onClientChange = value; }
    }

    public void RaisePostBackEvent(string eventArgument)
    {
        if (eventArgument == "LookupControl_LookupItemChanged")
        {
            if (this.LookupItemChanged != null)
            {
                this.LookupItemChanged(this, new EventArgs());
            }
        }
    }
}

public delegate void LookupItemChanged(object sender, EventArgs args);


[Serializable]
public class LookupControlItem
{
	private Guid _guid;
	private string _name = string.Empty;
	private int _typeCode;
	private string _typeName = string.Empty;

	public Guid Guid
	{
		get { return _guid; }
		set { _guid = value; }
	}

	public string Name
	{
		get { return _name; }
		set { _name = value; }
	}

	public int TypeCode
	{
		get { return _typeCode; }
		set { _typeCode = value; }
	}

	public string TypeName
	{
		get { return _typeName; }
		set { _typeName = value; }
	}
}